﻿#ifndef EMBDATA_H
#define EMBDATA_H

#include <QList>
#include <QByteArray>
#include <QApplication>
#include <QDir>
#include <QImage>
#include <qmath.h>
#include <QDebug>
#include <QFile>
#include <QFileInfo>
#include <QPainter>
#include <QRgb>
#include <QObject>
#include "machine/comm/datadef.h"
#include "machine/comm/crc16.h"
#include <QVector>
#include "datafile/datafiledsr.h"
#include "cfloat"

#include <QPair>
#include <QByteArray>
#include <QList>
#include <QVector>
#include <algorithm>
#include <QtGlobal>
#include <cmath>
#include <algorithm>
#include <functional> // for std::greater

#define ZERO    1e-6

#define MAX_EMB_STEP    121//四字节针步最大针步限制
#define DEFAULT_JUMP    70//默认针步大小
#define SEW_NEEDLE_NUM      2 //缝纫2个针杆
#define COLORTABLE_NUM  512//色序表

#define EMB_PREVIEW_SIDE    (32)     // 留边大小
#define TENTHOUSANDNEEDLE   100000

//#define EMB_SHOWDIRX    (1)   // X向显示坐标和数据坐标的差异
//#define EMB_SHOWDIRY    (1)    // Y向显示坐标和数据坐标的差异
#define OUTLINESTEPFACTOR  100 // 生成轮廓花样针步乘以的系数，单位是0.01，所以乘以100

#define PI10000 31416   //180度
#define PI20000 62832
#define ANGLECORR 10466 //60度对应的弧度值

#define MODE_THICKEN    0   //密针方式
#define MODE_LOCK       1   //锁针方式

#define NEEDLENONE      0  //无针
#define NEEDLELEFT      1  //左针
#define NEEDLERIGHT     2  //右针
#define NEEDLEDOUBLE    3  //双针
#define NEEDLENOTSET    4  //未设置
#define LAYOUTNEEDLENUM 16

// 辅助结构体
struct LineSegment {
    int indexA1; // a1在列表中的索引
    int indexA2; // a2的索引
    DsAbsItem a1;
    DsAbsItem a2;
    u8 ctrlType;
};

enum OverlapType {
    None,//无重叠
    Full,//完全重叠
    Partial_1,//部分重叠-len1部分len2
    Partial_2,//部分重叠-len2部分len1
    Contains_1,//包含-len1包含len2
    Contains_2//包含-len2包含len1
};


typedef union
{
    u8 buf8[4];
    u32 buf32;
} U32ToU8;

class EmbData: public QObject
{
    Q_OBJECT

public:
    EmbData();
    ~EmbData();

public:
    void clear();
    QByteArray & getDsDat();//得到转换后的ds16数据
    QByteArray getDispDat(double showWidth,double showHeight);//得到转换后的绘图数据
    inline DataDs16FileHead * getDsDatHead(){return m_pEmbDs16Head;}//得到转换后的ds16数据的文件头
    void setDsDatHeadFileID(u32 fileid);//设置数据区文件头的fileid
    void getAbsDatRangeXY();//得到绝对坐标的maxXY和minXY
    void appendAEmbAbsFile(QString filePath,QByteArray array,int mirror = 0);//附加一个绝对坐标的花样文件
    int addLockStitchs(u8 mode, u8 needles, u8 num);
    int angleCorrectionBak(s16 oft);//角度修正(老版本)
    int angleCorrectionXYBack(s32 px, s32 nx, s32 py, s32 ny);//x/y+-修正(老版本)
    void reFitByStep(s32 stepLen);//按固定针步重新拟合（用户可设置的参数，暂未用到）
    void reFitLine(s32 stepLen);//按固定针步重新拟合直线（用户可设置的参数）
    int moveStartPoint(short left, short front);//移动起始点，左边，前边
    QByteArray & lolaComp(s16 value);//罗拉补偿

public:
    inline QString getFileName(){return m_pEmbDs16Head->fileName;}//得到花版名称
    inline QString getFilePath(){return m_filePath;}//得到花版路径
    inline int getStitchNums(){return m_pEmbDs16Head->itemNums;}//得到数据的针数
    inline int getDatWidth(){return m_pEmbDs16Head->maxX - m_pEmbDs16Head->minX;}//得到数据的图形宽度
    inline int getDatHeight(){return m_pEmbDs16Head->maxY - m_pEmbDs16Head->minY;}//得到数据的图形高度
    inline int getMaxX(){return m_pEmbDs16Head->maxX;}//得到数据最大X+
    inline int getMinX(){return m_pEmbDs16Head->minX;}//得到数据最小X-
    inline int getMaxY(){return m_pEmbDs16Head->maxY;}//得到数据最大Y+
    inline int getMinY(){return m_pEmbDs16Head->minY;}//得到数据最小Y-
    inline int getBeginX(){return m_pEmbDs16Head->beginX;}
    inline int getBeginY(){return m_pEmbDs16Head->beginY;}
    inline int getAnchorX(){return m_pEmbDs16Head->anchorX;}//得到数据定位点
    inline int getAnchorY(){return m_pEmbDs16Head->anchorY;}//得到数据定位点

    inline void setSplitLen(u16 len){m_splitLen = len;}//分割数据长度
//    inline int setSplitLen(u16 len){return len;}//分割数据长度

public:
    void moveDataBeginPonit(s32 left, s32 front);
    void setAbsDat(QByteArray & dat);
    QByteArray &  getAbsDat(void);
    int getPosInfoFromNeedleIdx(int stitchIdx, int & posx, int & posy, int & colorIdx);
    void setStartPosition(int x, int y);//设置起始点
    void setAnchorPosition(int x, int y);//设置定位点

public:
    double getAngle(double x1, double y1, double x2, double y2);
    int setDatSizeChange(int dsx, int dsy);//设置尺寸变化
    int setMirror(int mirror);//设置镜像
    int setFLip(int mirror);//设置镜像

    int splittingArc(double posX1, double posY1,double posX2, double posY2,double xc, double yc, double rc,double dr1,double dr2,int step,QByteArray &cutData, DsAbsItem item);// 分割圆弧
    int splittingLine(double posX1, double posY1,double posX2, double posY2,int stepMin, int stepMax,QByteArray &cutData, DsAbsItem item);    // 分割直线

    // 偏心刀平板切割机补偿算法
    int setCutcontrastData();             // 增加对比数据
    int setCutCornerStep();               // 增加拐点数据
    int setCutEccentricCompensation();    // 偏心刀刀尖补偿
    int setCutAddCutterComption();        // 增加两端补偿
    int setCutRotaryCutterData();         // 增加转刀数据
    int setCutDecCornerStep();            // 删除拐点数据
    int setCutFitSplitStep();             // 分割切刀数据
    int setCutFitStepData();              // 拟合切刀数据

    // 飞行切割平板切割机补偿算法
    int outputCurStepData();                // 打印当前数据
    int setCut2CornerStep();                // 增加拐点数据
    int setCut2ModifyDataDir();             // 修改数据方向
    int setCut2FitSplitStep();              // 分割切刀数据
    int setCut2JudgInterval();              // 判断区间
    int setCut2AddCutterComption();         // 增加圆刀数据两端补偿
    int setCut2AddCutterComption2();        // 增加圆刀数据两端补偿 yct
    int setCut2SortNewData();               // 排序&组成新数据
    int setCut2AddOffsetData();             // 增加偏移数据
    int setCut2DelEdgeData();               // 删除上下边界的数据
    int setCut2CalMaxSpd();                 // 计算最大行进速度
    void setCut2ProcessEmbData();           // 修改重叠切割线段为偏移线段
    int setCut2AddDistanData();             // 增加距离数据(结束码), 用于存放当前窗口中,每个点距离最左边的距离
    void setCut2RemoveOverLapLines();      // 修改重叠切割线段为偏移线段
    void setCut2recalculateAngles();        // 重新计算角度

    void recalculateAngles();               // 重新计算角度

    //计算角度ar
    s32 calculateAngles(double curX, double curY, double lastX, double lastY); //计算绝对角度ar
    //切割结尾补偿  移动结尾点
    void cutDataEndCompensate(DsAbsItem &curItem,DsAbsItem &preItem,double comDistance);
    //切割结尾小横切
    void cutDataVertCut(DsAbsItem &curItem,double comDistance, QByteArray & cutAbsData,int &newstepnum);
    //切割开头的补偿  移动起始点
    void cutDataStartCompensate(DsAbsItem &curItem,DsAbsItem &preItem, DsAbsItem &nextItem, double comDistance);

    bool isCutCtrl(u8 &ctrl);

    void optimizationOrder(QVector<QVector<QByteArray>> &visited,int winNum);//数据优化顺序
    void addPenData(QVector<QVector<QByteArray>> &pVisited,QVector<QVector<QByteArray>> &rVisited,QVector<QVector<QByteArray>> &sVisitedint, int winNum,double xWin,double xminPos,double yminPos);  //在空白窗口增加画笔数据

    u32 CalcDisplacement(u32 pps1, u32 pps2, u32 calcTime);
    s16 Rot001ToPitk(s32 ang001);
    int setCutMoveParameters();           // 计算切刀移动参数

    int setRotate(int dr);//设置旋转
    int setRotate90(bool flag);//旋转+-90度  flag :true代表顺时针方向
    int getNextElementIndex(int curIndex);//获得下一个图元的第一缝纫针步
    int getPreOrThisElementIndex(int curIndex);//上一个图元(当前为跨步时)或当前图元(当前为缝纫时)的第一缝纫针步

private:
    void splitBorderStitchAndAdd(QByteArray & dat,int bx,int by,int ex,int ey);//分割边框针步并添加
    //此函数转换传入的绝对坐标值，是否取镜像及反复时数据之间的间距
    void convertAbsDat(QByteArray & dat,int mirror = 0);
    int calcLine(double x0, double y0, double x1, double y1, s16 step, QByteArray &absAry, DsAbsItem item);

    int createEmbDs16FromAbs();//生成DS16数据
    int reCalcDataChecksum();//重新计算文件CRC
    void drawNeedleIdxPen(int x, int y, QPainter &painter);//绘制针数索引的跟踪笔
    void drawFork(int x, int y, QPainter &painter);//绘制针数索引的十字
    void drawFork(int x, int y, QPainter &painter,int index);//绘制针数索引的十字
    void eraseNeedleIdxPen(QPainter &painter);//擦除针数索引的跟踪笔
    void eraseNeedleIdxPen(QPainter &painter,int index);//擦除针数索引的跟踪笔

private:
    void getCurvePointFillLine(QList<DsAbsItem> &inList, double indRunLen,QList<DsAbsItem> &outList);
    int getTotalDistanceFillLine(QList<DsAbsItem> *pPointList, double &dTotal);
    bool getPointInSectFillLine(const DsAbsItem &p1, const DsAbsItem &p2, const double &d, DsAbsItem &outp);
    //距p1点距离为d的点
    // d > s : out_p在p2延长线上
    // s >= d >= 0 : out_p在p1、p2线段上
    // d < 0 : out_p在p1延长线上
    bool getPointAtSect(const DsAbsItem &p1, const DsAbsItem &p2, const double &d, DsAbsItem &outp);

public:
    int m_editedflag;//数据被编辑的标志
    int m_spaceX;//横向间隙
    int m_spaceY;//纵向移动距离

    int m_endPosX;//花样最后点坐标
    int m_endPosY;//花样最后点坐标

//用于调节颜色
#if(1)
    QString m_selfilename;
#endif

    double m_minX;
    double m_maxX;
    double m_minY;
    double m_maxY;

    u8 m_addcorner;//拐角增加针步标志-多针旋梭机
    u8 m_cutcorner;//拐角分割针步标志-多针旋梭机
    u16 m_cornerPX;//拐角x+补偿量-多针旋梭机
    u16 m_cornerNX;//拐角x-补偿量-多针旋梭机
    u16 m_cornerPY;//拐角y+补偿量-多针旋梭机
    u16 m_cornerNY;//拐角y-补偿量-多针旋梭机

private:
    QByteArray m_embAbsData;    // 转换后的绝对坐标数据
    QByteArray m_embDs16Data;//发给下位机的ds16数据（需要转换）
    int m_totalJumpNeedle;//总跳针数
    DataDs16FileHead * m_pEmbDs16Head;//ds16    文件头     //数据转换用的都是DataDs16FileHead
    double m_factor;//绘制数据与实际数据的缩放率
    u32 m_fileid;
    u16 m_splitLen;

    int m_winnums;//飞行平板切割机器-窗口划分个数

    QByteArray m_oneDispDat;    //飞梭机单个绘制数据

//图形预览、刷新
public:
    //显示所有线迹（原色显示）
    //显示所有线迹（有效区域内的显示原色，其余显示灰色）
    //显示所有线迹（执行过的显示原色，其余显示灰色）
    //刷新部分线迹（缝纫中进度显示）
    enum DISP_MODE {DISP_ALL_NORMAL = 0, DISP_ALL_AREA, DISP_ALL_EXEC, DISP_EXECING};
    enum DRAW_MODE {DRAW_VIEW = 0, DRAW_PREVIEW};//绘制模式(非预览模式、预览模式)

public:
    int setViewInfo(int width, int height);//设置视图尺寸(透明背景)
    void setViewInfo(QPixmap pix);//设置视图(带背景图片背景)
    void setEmbData(int type,int redraw = 0);//重置数据
                                                            //是否重绘      //是否为渐变
    void setDispMode(DISP_MODE dispmode = DISP_ALL_NORMAL, int redraw = 0);//设置预览模式
    void setDrawMode(DRAW_MODE drawmode = DRAW_VIEW);//设置绘制模式

    void setExecIndex(int index);//设置进度显示数据
    void reDraw();//重新绘图

public:
    inline QPixmap getPreviewImage(){return m_canvas;}//返回预览图片
    int setCut2ArrangeData();

private:
    int createDispFromEmbDs16Dat(QByteArray & ds16dat);//创建显示用的数据（为了快速显示）
    int createDispFromEmbDs16DatForHeadInfo(QByteArray & ds16dat);
    int drawImageByDispFile();//用显示数据画图(是否渐变显示)
    int drawImageByOneStepLotLine();
    int findMaxSpHead(DsrHeadEx62 & head,int headCount);
    void drawMultiTrack(QPainter &painter); //绘制多机头的跟踪图案
    void drawMultiLine(QPainter &painter, QPen &pen, QRgb rgb,  int index); //绘制多机头的线迹

public:
    void getOneDispDat(QByteArray &ds16dat);   //得到一个绘制数据
    void resetLayoutDispDat(unsigned char *arrayNeedle1,unsigned char *arrayNeedle2,unsigned char *arrayNeedle3,int leftRightNeedleSpace,int needlesSpace,int needleLayoutSpace12,int needleLayoutSpace23,int reDat = 0);
    int createDispFromEmbDs16DatForFlyShuttle(int initFlag = 0);//飞梭机绘制数据

    static bool checkFirstEndNeedle(QByteArray ary);//确认起终点的x值是否一致
    QByteArray rotationAngleAdjustment(int flag);//根据flag对数据进行旋转角度调整
    void setpressureHighsAndAnchorPosition(int x,int y,short preH2=0, short preH3=0, short preH5=0, short preH6=0, short preH7=0, short preH8=0, short preH9=0);

    int cornerAddNeedleStep(QByteArray & ds16dat);  //多针机-拐角分割/添加针步
    int angleCorrection(QByteArray & ds16dat);      //多针机-角度修正(新版本)

    int setCut2RemoveErroData();//飞行平板切割机-剔除数据
    int setCut2RemoveErroData2();//飞行平板切割机-剔除数据-重叠线段函数后使用
    void setCut2recalculateAngles2();
    int setCut2ArrangeDataForNew();
    int setCut2ArrangeDataForNewPenAndKnife();
    void setCut2WinComp();
    int setCut2ArrangeDataForPen();
    int setCut2ArrangeDataForKnife();
    int setCut2AddCutterComption22();
    void cutDataEndCompensate2(DsAbsItem &curItem, DsAbsItem &preItem, double comDistance, double maxY, double minY);
    void cutDataStartCompensate2(DsAbsItem &curItem, DsAbsItem &preItem, DsAbsItem &nextItem, double comDistance, double maxY, double minY);
private:
    int m_type; //机型
    int m_penX, m_penY;//执行过程中绘制跟踪笔的坐标索引

    QPixmap m_canvas;//预览图片
    QPixmap m_penPix;//跟踪笔绘制的临时区域
    QVector<QPixmap> m_penHeadPix;
    QVector<QPoint> m_penPoint;

    int m_viewWidth;
    int m_viewHight;

    QString m_filePath;//文件路径

private:
    QByteArray m_dispDat;//绘制图形的绝对数据(进行缩放的)
    QVector<Disp_HeadItem> m_headDispDate; //五头机绘图针步
    int m_stitchIndex;  //进度步数
    int m_dispIndex; //当前index
    DISP_MODE m_dispMode;
    DRAW_MODE m_drawMode;

    QByteArray m_dispDatFront;//飞梭机前排数据
    QByteArray m_dispDatMiddle;//飞梭机中排数据
    QByteArray m_dispDatBehind;//飞梭机后排数据

    double m_dispMinX;
    double m_dispMaxX;
    double m_dispMinY;
    double m_dispMaxY;
signals:
    void siDrawNeedleIdx(int idx);

};

#endif // EMBDATA_H
